import gtk,gobject
import WindowTemplate
import Shares
import Locations

class MainWindow(WindowTemplate.WindowTemplate):
    """The MAIM Main Window"""
    
    def __init__(self,controller):
        """constuctor"""
        
        WindowTemplate.WindowTemplate.__init__(self,controller)
        self.create_window()
        self.add_accel_group(self.controller.uimanager.accel_group)
        
        # Connect to locations callbacks
        self.locations.connect('add',self.add_location)
        self.locations.connect('set',self.set_location)
        self.locations.connect('remove',self.remove_location)
        
        # Connect to shares callbacks
        self.shares.connect('add',self.add_share)
        self.shares.connect('set',self.set_share)
        self.shares.connect('remove',self.remove_share)
        self.shares.connect('set::mount',self.set_share)
        self.shares.connect('set::unmount',self.set_share)
        self.shares.connect('set::latency',self.set_share)
        self.shares.connect('set::automount',self.set_share)
        
        # Connect to config callbacks
        self.current_location_callback = self.config.connect('set::NETWORK::CURRENT LOCATION',self.set_current_location_callback)
        self.network_state_callback = self.config.connect('set::NETWORK::STATE',self.set_network_state_callback)
        
    def create_window(self):
        '''create and add widgets to the window'''
        
        self.set_title("Miam")
        self.load_pos()
        
        self.create_treeview()
        self.create_expander()
        self.expander.set_no_show_all(True)
        #Global VBox
        global_vbox = gtk.VBox()
        
        #Menu
        global_vbox.pack_start(self.controller.menubar,False,False)
        
        #Toolbar
        global_vbox.pack_start(self.controller.toolbar,False,False)
        
        #Current Location Label
        self.lbl_current_location = gtk.Label()
        global_vbox.pack_start(self.lbl_current_location,False,False)
        
        global_hbox = gtk.HBox()
        #Treeview
        scrolled_window = gtk.ScrolledWindow()
        scrolled_window.set_policy(gtk.POLICY_NEVER,gtk.POLICY_AUTOMATIC)
        scrolled_window.add(self.treeview)
        global_hbox.pack_start(scrolled_window)
        
        #Expander
        global_hbox.pack_start(self.expander)
        
        global_vbox.pack_start(global_hbox)
        
        self.add(global_vbox)
        self.show_all()
        
    def create_treeview(self):
        '''create the main treeview with it's treemodel and treemodelsort'''
        
        # Treemodel
        self.treemodel = gtk.TreeStore( gobject.TYPE_INT,
                                        gobject.TYPE_STRING,
                                        gobject.TYPE_STRING,
                                        gobject.TYPE_STRING,
                                        gobject.TYPE_BOOLEAN)
        
        self.fill_treemodel()
        
        # Treemodelsort
        self.treemodelsort = gtk.TreeModelSort(self.treemodel)
        self.treemodelsort.set_sort_func(999, self.sort_treemodel)
        self.treemodelsort.set_sort_func(998, self.sort_treemodel)
        self.treemodelsort.set_sort_column_id(999,gtk.SORT_ASCENDING)
        
        # Cell renderers
        cr_name = gtk.CellRendererText()
        cr_mounted = gtk.CellRendererPixbuf()
        cr_type = gtk.CellRendererText()
        cr_latency = gtk.CellRendererText() 
        cr_automount = gtk.CellRendererToggle()
        cr_automount.connect('toggled', self.cb_automount_callback)
        
        # Columns
        col_name = gtk.TreeViewColumn("Name", cr_name, text=1)
        
        col_mounted = gtk.TreeViewColumn("Mounted", cr_mounted)
        col_mounted.set_cell_data_func(cr_mounted, self.get_mounted_pixbuf)
                
        col_type = gtk.TreeViewColumn("Type", cr_type, text=2)
        
        col_latency = gtk.TreeViewColumn("Latency",cr_latency, text=3)
        
        col_automount = gtk.TreeViewColumn("Auto", cr_automount)
        col_automount.add_attribute(cr_automount, "active", 4)

        
        # Treeview
        self.treeview = gtk.TreeView(self.treemodelsort)
        self.treeview.append_column( col_name )
        self.treeview.append_column( col_mounted )
        self.treeview.append_column( col_type )
        self.treeview.append_column( col_latency )
        self.treeview.append_column( col_automount )
        self.treeview.connect("cursor-changed",self.row_changed_callback)
        self.treeview.connect("unselect-all",self.row_changed_callback)
        self.treeview.connect("row-activated",self.row_activated_callback)
        self.treeview.expand_row(0,False)
    
        self.treeview_accel_group = gtk.AccelGroup()
        self.treeview_accel_group.connect_group(gtk.keysyms.Delete,0, gtk.ACCEL_VISIBLE, self.suppr_callback)
        self.add_accel_group(self.treeview_accel_group)
        
    def get_mounted_pixbuf(self, col, cr, model, iter):
        path = self.treemodelsort.get_path(iter)
        if path: 
            if len(path) == 2:
                share = self.shares[model.get_value(iter,0)]
                if share.mounted:
                    cr.set_property('stock-id', gtk.STOCK_APPLY)
                else:
                    cr.set_property('stock-id', gtk.STOCK_CANCEL)
            else:
                cr.set_property('pixbuf', None)
            
    def sort_treemodel(self, model, iter1, iter2):
        item1 = model.get_value(iter1,1)
        id_item1 = model.get_value(iter1,0)
        
        if not item1:
            return 0
        else:
            item1 = item1.lower()
        
        item2 = model.get_value(iter2,1)
        id_item2 = model.get_value(iter2,0)
        
        if not item2:
            return 0
        else:
            item2 = item2.lower()
        
        # Everywhere en 1er
        if model.iter_depth(iter1) == 0 and id_item1 == 0:
            return -1
        if model.iter_depth(iter2) == 0 and id_item2 == 0:
            return 1
        
        # Curr loc en 2eme
        if self.config.network['CURRENT LOCATION']:
            if model.iter_depth(iter1) == 0 and id_item1 == self.config.network['CURRENT LOCATION'].id:
                return -1
            if model.iter_depth(iter2) == 0 and id_item2 == self.config.network['CURRENT LOCATION'].id:
                return 1
        
        # tri alphabetique pour la suite
        if item1 < item2 :
            return -1
        elif item1 > item2 :
            return 1
        else:
            return 0
    
    def create_expander(self):
        '''create the expander with it's child widget'''
        
        self.expander = gtk.Expander(label="Info")
                
        # Location vbox
        lbl_location_name = gtk.Label("Name :")
        self.lbl_location_name = gtk.Label("")
        location_hbox_name = self.build_hbox((lbl_location_name,self.lbl_location_name))
        # Location params expander
        self.param_expander = gtk.Expander(label="Params")
        self.expander_location_vbox = self.build_vbox((location_hbox_name,self.param_expander))
        self.expander_location_vbox.show_all()
        
        # Share vbox
        lbl_share_name = gtk.Label("Name :")
        self.lbl_share_name = gtk.Label("")
        share_hbox_name = self.build_hbox((lbl_share_name,self.lbl_share_name))
        
        lbl_share_location = gtk.Label("Location :")
        self.lbl_share_location =gtk.Label("")
        share_hbox_location = self.build_hbox((lbl_share_location,self.lbl_share_location))
        
        lbl_share_server = gtk.Label("Server :")
        self.lbl_share_server =gtk.Label("")
        share_hbox_server = self.build_hbox((lbl_share_server,self.lbl_share_server))
        
        lbl_share_mountpoint = gtk.Label("Mount Point :")
        self.lbl_share_mountpoint =gtk.Label("")
        share_hbox_mountpoint = self.build_hbox((lbl_share_mountpoint,self.lbl_share_mountpoint))
        
        lbl_share_mounted = gtk.Label("Mounted :")
        self.lbl_share_mounted =gtk.Label("")
        share_hbox_mounted = self.build_hbox((lbl_share_mounted,self.lbl_share_mounted))
        
        lbl_share_protocol = gtk.Label("Protocol :")
        self.lbl_share_protocol =gtk.Label("")
        share_hbox_protocol = self.build_hbox((lbl_share_protocol,self.lbl_share_protocol))
        
        lbl_share_path = gtk.Label("Path :")
        self.lbl_share_path = gtk.Label("")
        self.share_hbox_path = self.build_hbox((lbl_share_path,self.lbl_share_path))
        
        lbl_share_domain = gtk.Label("Domain :")
        self.lbl_share_domain = gtk.Label("")
        self.share_hbox_domain = self.build_hbox((lbl_share_domain,self.lbl_share_domain))
        
        self.expander_share_vbox = self.build_vbox((share_hbox_name,share_hbox_location,share_hbox_server,share_hbox_mountpoint,share_hbox_mounted,share_hbox_protocol,self.share_hbox_path,self.share_hbox_domain),False,0,False,False,0)
        self.expander_share_vbox.show_all()
        
    def fill_treemodel(self):
        '''clear then fill the treemodel'''
        
        self.treemodel.clear()
        for id,location in self.locations:
            self.add_location(self.locations,location)
        for id,share in self.shares:
            self.add_share(self.shares, share)
    
    def fill_expander(self,item):
        '''clear then fill the expander with the gived item'''
        
        if self.expander.get_child():
            self.expander.remove(self.expander.get_child()) 
        
        if isinstance(item, Locations.Location):
            self.lbl_location_name.set_text(item.name)
            param_vbox = gtk.VBox()
            if self.param_expander.get_child(): # clear the param expander if needed
                self.param_expander.remove(self.param_expander.get_child())
            # fill param expander
            for value in item.dns:
                param_vbox.pack_start(self.build_hbox((gtk.Label("DNS :"),gtk.Label(value))))
            for value in item.public_addr:
                param_vbox.pack_start(self.build_hbox((gtk.Label("IP Public :"),gtk.Label(value))))
            for value in item.local_addr:
                param_vbox.pack_start(self.build_hbox((gtk.Label("IP Local :"),gtk.Label(value))))                                            
            param_vbox.show_all()
            self.param_expander.add(param_vbox)
            self.expander.add(self.expander_location_vbox)
        
        elif isinstance(item, Shares.Share):
            self.lbl_share_name.set_text(item.name)
            location_item = item.location
            self.lbl_share_location.set_text(location_item.name)
            self.lbl_share_server.set_text(item.server)
            self.lbl_share_mountpoint.set_text(item.mount_point)
            if item.mounted:
                self.lbl_share_mounted.set_text("Yes")
            else:
                self.lbl_share_mounted.set_text("No")
            self.lbl_share_protocol.set_text(item.protocol)
            if item.path != "":           
                self.lbl_share_path.set_text(item.path)
                self.share_hbox_path.show_all()
            else:
                self.share_hbox_path.hide_all()
            
            if item.domain != "":           
                self.lbl_share_domain.set_text(item.domain)
                self.share_hbox_domain.show_all()
            else:
                self.share_hbox_domain.hide_all()    
                
            self.expander.add(self.expander_share_vbox)
    
    # Treeview special getter
    def get_item_by_cursor(self):
        '''return the item currently selected in the treeview'''
       
        path = self.treeview.get_cursor()[0]
        if path:
            if len(path) == 1:
                    return self.locations[self.treemodelsort[path][0]]
            if len(path) == 2:
                    return self.shares[self.treemodelsort[path][0]]
        
    def get_item_by_path(self,path):
        '''return the item pointed by the gived ( treemodel !!! ) path'''
        
        if len(path) == 1:
                return self.locations[self.treemodel[path][0]]
        if len(path) == 2:
                return self.shares[self.treemodel[path][0]]
        
    def get_location_iter_by_id(self,location_id):
        '''return the gtk.Treeiter of the gived location id'''
        
        iter = self.treemodel.get_iter_root()
        while iter != None:
            if self.treemodel.get_value(iter,0) == location_id:
                return iter
            iter = self.treemodel.iter_next(iter)
                
    def get_share_iter_by_id(self,share_id,location_id=None):
        '''return the gtk.Treeiter of the gived share id, give a location id makes it faster'''
        
        if location_id == None:
            # search iter in every locations by a recursive call
            for location_id,location in self.locations:
                iter = self.get_share_iter_by_id(share_id, location_id)
                if iter:
                    return iter
        else:
            # search iter in the gived location
            iter = self.treemodel.iter_children(self.get_location_iter_by_id(location_id))
            while iter != None:
                if self.treemodel.get_value(iter,0) == share_id:
                    return iter
                iter = self.treemodel.iter_next(iter)

    def get_latency_display(self,share):
        if isinstance(share.latency,int):
            return "%s ms" % share.latency
        if isinstance(share.latency,Exception):
            return share.latency.__class__.__name__
        else:
            return ""
    ###
#    def save_expanded_locations(self):
#        self.expended_rows = []
#        iter = self.treemodel.get_iter_first()
#        while iter:
#            path = self.treemodel.get_path(iter)
#            if self.treeview.row_expanded(path):
#                self.expended_rows.append(path)
#            iter = self.treemodel.iter_next(iter)
#        
#    def load_expanded_locations(self):
#        pass
    ###
    
    #Locations callbacks:
    def add_location(self,locations, location):
        '''add a location to the treeview'''
        
        self.treemodel.append(None,(location.id,location.name,"","",location.automount))
    
    def remove_location(self,locations,id):
        '''remove a location from the treeview'''
        
        self.treemodel.remove(self.get_location_iter_by_id(id))
        
    def set_location(self,locations,location):
        '''refresh the gived location row in the treeview'''
        
        self.treemodel.set(self.get_location_iter_by_id(location.id),1,location.name,4,location.automount)
        if self.get_item_by_cursor() == location: # refill the expander only the current selected row is the gived location one
            self.fill_expander(location)       
        ###
        self.treeview.expand_all()
        ###
    #Shares callbacks:
    def add_share(self,shares, share):
        '''add a share to the treeview'''
        self.treemodel.append(self.get_location_iter_by_id(share.location.id),(share.id,share.name,share.protocol,self.get_latency_display(share),share.automount))

    def remove_share(self,shares,location,share_id):
        '''remove a share from the treeview'''
        
        self.treemodel.remove(self.get_share_iter_by_id(share_id,location.id))
        
    def set_share(self,shares,share):
        '''refresh the share row in the treeview, move it if it is in the wrong location'''
        # get the current location where the share now is
#        self.save_expanded_locations()
        share_iter = self.get_share_iter_by_id(share.id)
        current_share_path = self.treemodel.get_path(share_iter)
        current_location_path = (current_share_path[0],)
        current_location = self.get_item_by_path(current_location_path)
        if current_location == share.location:
            self.treemodel.set(self.get_share_iter_by_id(share.id,share.location.id),1,share.name,2,share.protocol,3,self.get_latency_display(share),4,share.automount)
        else:
            self.remove_share(self.shares, current_location, share.id)
            self.add_share(self.shares, share)
        if self.get_item_by_cursor() == share: # refill the expander only the current selected row is the gived share one
            self.fill_expander(share)
        
    def set_current_location_callback(self,config,new_location,old_location):
        if new_location:
            msg = "%s ( %s / %s )" % (self.config.network['CURRENT LOCATION'].name,self.config.network['PUBLIC ADDR'],str(self.config.network['LOCAL ADDR']))
            self.lbl_current_location.set_text(msg)
            # expand the current location
            if self.config.network['CURRENT LOCATION']:
                ### Nasty call for the treemodelsort to resort himself
                self.treemodelsort.set_sort_column_id(998,gtk.SORT_ASCENDING)
                self.treemodelsort.set_sort_column_id(999,gtk.SORT_ASCENDING)
                ###
                if self.config.network['CURRENT LOCATION'].id:
                    self.treeview.expand_row(1,False)
                                
    def set_network_state_callback(self,config,new_state,old_state):
        if not new_state:
            self.lbl_current_location.set_text('Network Unreachable')
    
    #Widget callbacks
    def cb_automount_callback(self,widget,sorted_path):
        '''automount checkbox callback'''
        # convert gived string sorted path into a non-sorted tuple path
        if len(sorted_path) > 1 :
            sorted_path = tuple([int(i) for i in sorted_path.split(':')])
        elif len(sorted_path) == 1 :
            sorted_path = (int(sorted_path),)
        path = self.treemodelsort.convert_path_to_child_path(sorted_path)
        share = self.get_item_by_path(path)
        self.shares.set_automount(share, not self.treemodel[path][4])
        
    def row_activated_callback(self,treeview,path,column):
        item = self.get_item_by_path(self.treemodelsort.convert_path_to_child_path(path))
        if isinstance(item,Shares.Share):
            self.controller.open_share(item)
            
    def row_changed_callback(self,widget):
        '''fill expander on selected row change'''
        item = self.get_item_by_cursor()
        self.fill_expander(item)
    
    def suppr_callback(self,*args):
        item = self.get_item_by_cursor()
        if isinstance(item,Locations.Location):
            if item.id:
                self.controller.remove_location(item)
        elif isinstance(item,Shares.Share):
            self.controller.remove_share(item)
    
    def load_pos(self):
        if self.config.user['MAIN WINDOW POS']:
            if self.config.user['MAIN WINDOW SIZE']:
                x,y = self.config.user['MAIN WINDOW SIZE']
                self.resize(x,y)
            x,y = self.config.user['MAIN WINDOW POS']
            self.move(x,y)
        else:
            self.set_size_request(self.config.glob['MAIN WINDOW WIDTH'],self.config.glob['MAIN WINDOW HEIGHT'])
    
    def save_pos(self):
        self.config.user['MAIN WINDOW POS'] = self.get_position()
        self.config.user['MAIN WINDOW SIZE'] = self.get_size()
    
    def close(self):
        self.save_pos()
        self.config.disconnect(self.current_location_callback)
        self.config.disconnect(self.network_state_callback)
        super(self.__class__,self).close()
        